package app.caihan.scframe.base.fragment

import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.annotation.MainThread
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import app.caihan.scframe.R
import app.caihan.scframe.base.viewmodel.BaseViewModel
import app.caihan.scframe.common.loadinghelper.LoadingHelper
import app.caihan.scframe.ktx.getVmClazz
import app.caihan.scframe.util.CoroutineState
import app.caihan.scframe.util.NetworkStateManager
import app.caihan.scframe.util.StatusBarConfig
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.customview.customView
import com.afollestad.materialdialogs.customview.getCustomView
import com.afollestad.materialdialogs.lifecycle.lifecycleOwner
import com.blankj.utilcode.util.BarUtils
import com.blankj.utilcode.util.ColorUtils
import com.blankj.utilcode.util.KeyboardUtils
import org.jetbrains.anko.toast

/**
 * ViewModelFragment基类
 * 请使用FragmentContainerView代替FrameLayout作为Fragment的容器
 *
 * 你真的会用Fragment吗 -> [https://juejin.im/post/6844904079697657863]
 * ViewPager2重大更新 -> [https://juejin.im/post/6844903843658989581]
 *
 * ViewPager2的offScreenPageLimit默认值为OFFSCREEN_PAGE_LIMIT_DEFAULT,
 * 当setOffscreenPageLimit为OFFSCREEN_PAGE_LIMIT_DEFAULT时候会使用RecyclerView的缓存机制。
 * 默认只会加载当前显示的Fragment,而不会像 ViewPager 一样至少预加载一个item.当切换到下一个item的时候，
 * 当前 Fragment 会执行 onPause 方法，而下一个 Fragment 则会从 onCreate 一直执行到 onResume 。
 * 当再次滑动回第一个页面的时候当前页面同样会执行onPuase，而第一个页面会执行onResume
 * 所以ViewPager2中默认关闭了预加载机制,只需要将懒加载的内容放到onStart/onResume中即可
 *
 * 如何理解offscreenPageLimit对Fragment的影响，
 * 假设offscreenPageLimit=1，这样ViewPager2最多可以承托3个ItemView，再加上2个缓存的ItemView，就是5个，
 * 由于offscreenPageLimit会在ViewPager2两边放置一个，所以向前最多承载4个，
 * 向后最多能承载1个(预加载对Fragment没有影响，所以不计算)，这样很自然就是第5个时候，回收第1个；
 * 所以如果Launcher页使用的是5个tab的话,offscreenPageLimit设置成2就可以确保都不会被非正常回收
 *
 * 在前后台切换的时候走 onStop -> onStart 当前显示的 Fragment 会再走一个onResume方法
 *
 * onAttach -> Lifecycle.State.INITIALIZED
 * onCreate -> Lifecycle.State.CREATED
 * onViewCreated -> Lifecycle.State.CREATED
 * onActivityCreated -> Lifecycle.State.CREATED
 * onStart -> Lifecycle.State.STARTED
 * onResume -> Lifecycle.State.STARTED
 *
 * @author Seven-C
 * @date 2020/7/27
 */
abstract class BaseVmFragment<VM : BaseViewModel> : Fragment(), IBaseFragment {

    protected val simpleFragmentTag = javaClass.simpleName

    /**
     * 是否第一次加载
     */
    private var isFirst: Boolean = true

    val mViewModel: VM by lazy { createViewModel() }

    protected lateinit var loadingHelper: LoadingHelper

    /**
     * 独立设置状态栏
     */
    private var statusBarConfig: StatusBarConfig? = null

    private val progressDialog by lazy {
        context?.let {
            MaterialDialog(it)
                .cancelable(false)
                .cornerRadius(8f)
                .customView(R.layout.scframe_progress_dialog_view, noVerticalPadding = true)
                .lifecycleOwner(this)
                .maxWidth(R.dimen.dialog_width)
        }
    }


    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val rootView = inflater.inflate(bindLayoutId(), container, false)
        loadingHelper = LoadingHelper(rootView)
        loadingHelper.setOnReloadListener { onReload() }
        return loadingHelper.decorView
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        isFirst = true
        setDataBindingVariable()
        initView(savedInstanceState)
        registerUiChange()
        initData()
    }

    /**
     * 绑定DataBinding数据 Fragment执行onViewCreated后触发
     */
    @MainThread
    protected open fun setDataBindingVariable() {
    }

    /**
     * Fragment执行onCreate后触发的方法
     */
    @MainThread
    protected open fun initData() {
    }

    /**
     * 重载页面,在loadingHelper的ErrorAdapter布局中调用
     */
    protected open fun onReload() {}

    override fun onResume() {
        super.onResume()
        onVisible()
    }

    override fun onPause() {
        super.onPause()
        //关闭软键盘
        KeyboardUtils.hideSoftInput(requireActivity())
    }

    /**
     * 创建viewModel
     */
    private fun createViewModel(): VM {
        return ViewModelProvider(this).get(getVmClazz(this, 0))
    }

    /**
     * 是否需要懒加载
     */
    private fun onVisible() {
        if (lifecycle.currentState == Lifecycle.State.STARTED && isFirst && !isHidden) {
            //延迟加载0.12秒加载 避免fragment跳转动画和渲染ui同时进行，出现些微的小卡顿
            view?.post {
                createObserver()
                lazyLoadData()
                //在Fragment中，只有懒加载过了才能开启网络变化监听
                lifecycle.addObserver(NetworkStateManager.instance)
                NetworkStateManager.instance.networkState.observeInFragment(this, Observer {
                    //不是首次订阅时调用方法，防止数据第一次监听错误
                    if (!isFirst) {
                        onNetworkStateChanged(it)
                    }
                })
                isFirst = false
            }
        }
        setStatusBarStyle()
    }

    /**
     * 注册 UI 事件
     */
    private fun registerUiChange() {
        mViewModel.statusLiveData.observe(viewLifecycleOwner, Observer {
            when (it.state) {
                CoroutineState.FINISH.state -> loadingHelper.showContentView()
                CoroutineState.START.state -> loadingHelper.showLoadingView()
                CoroutineState.REFRESH.state -> loadingHelper.showLoadingView()
                CoroutineState.ERROR.state -> loadingHelper.showErrorView()
            }
        })
    }

    /**
     * 默认是会开启沉浸式模式,如果是
     */
    protected open fun getStatusBarConfig(): StatusBarConfig? {
        return StatusBarConfig()
    }

    protected open fun setStatusBarConfig(config: StatusBarConfig, isUpdate: Boolean = false) {
        statusBarConfig = config
        if (isUpdate) setStatusBarStyle()
    }

    /**
     * 框架默认使用白色导航栏,黑色导航栏字体,并且会对根布局进行一个MarginTop的操作
     */
    private fun setStatusBarStyle() {
        if (lifecycle.currentState == Lifecycle.State.STARTED && !isHidden) {
            view?.post {
                setStatusBar()
            }
        }
    }

    private fun setStatusBar() {
        if (statusBarConfig == null) statusBarConfig = getStatusBarConfig()
        statusBarConfig?.let {
            //isLightMode true=状态栏黑色字体,false=状态栏白色字体(系统默认)
            val isLightMode = BarUtils.isStatusBarLightMode(requireActivity())
            if (isLightMode != it.isDarkFont) {
                BarUtils.setStatusBarLightMode(requireActivity(), it.isDarkFont)
            }
            BarUtils.setStatusBarColor(requireActivity(), ColorUtils.getColor(it.statusBarColor))
            BarUtils.addMarginTopEqualStatusBarHeight(this@BaseVmFragment.view!!)
        }
    }

    /**
     * 网络变化监听 子类重写
     */
    protected open fun onNetworkStateChanged(netState: Boolean) {}

    fun toast(message: CharSequence) {
        requireActivity().toast(message)
    }

    /**
     * 打开等待框
     */
    protected fun showProgressDialog(message: String = "") {
        progressDialog?.run {
            if (!isShowing) {
                if (message.isNotEmpty()) {
                    getCustomView().run {
                        this.findViewById<TextView>(R.id.tvTip).text = message
                    }
                }
                show()
            }
        }
    }

    /**
     * 关闭等待框
     */
    protected fun dismissProgressDialog() {
        progressDialog?.run { if (isShowing) dismiss() }
    }
}